use std::thread;
use std::time::Duration;

fn simulated_expensive_calculation(intensity: u32) -> u32 {
    println!("calculating slowly...");
    thread::sleep(Duration::from_secs(2));
    intensity
}

fn generate_workout(intensity: u32, random_number: u32) { 
    // let mut expensive_result = cached_expensive_calculation(intensity);
    // 闭包调用
    // let expensive_closure = |num| {
    //     println!("calculating slowly...");
    //     thread::sleep(Duration::from_secs(2));
    //     num
    // };
    // 使用cacher
    let mut expensive_result = Cacher::new(|num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    });
    if intensity < 25 {
        println!(
            "Today, do {} pushups!",
            // expensive_closure(intensity)
            expensive_result.value(intensity)
        );
        println!(
            "Next, do {} situps!",
            // expensive_closure(intensity)
            expensive_result.value(intensity)
        );
    } else {
        if random_number == 3 {
            println!("Take a break today! Remember to stay hydrated!");
        } else {
            println!(
                "Today, run for {} minutes!",
                // expensive_closure(intensity)
                expensive_result.value(intensity)
            );
        }
    }
    
}


fn main() {
    let simulated_user_specified_value = 25;
    let simulated_random_number = 7;
    simulated_expensive_calculation(simulated_user_specified_value);
    generate_workout(simulated_user_specified_value, simulated_random_number);
}


/// 缓存计算结果的结构体
/// 
/// # 泛型参数
/// - T: 实现了Fn(u32) -> u32 trait的闭包或函数
struct Cacher<T>
where
    T: Fn(u32) -> u32,
{
    /// 用于计算的闭包或函数
    calculation: T,
    /// 缓存的计算结果
    value: Option<u32>,
}

impl<T> Cacher<T>
where
    T: Fn(u32) -> u32,
{
    /// 创建一个新的Cacher实例
    /// 
    /// # 参数
    /// - calculation: 用于计算的闭包或函数
    fn new(calculation: T) -> Cacher<T> {
        Cacher {
            calculation,
            value: None,
        }
    }
    
    /// 获取计算结果
    /// 
    /// # 参数
    /// - arg: 传递给计算函数的参数
    /// 
    /// # 返回值
    /// 返回计算结果，如果已有缓存则直接返回，否则计算并缓存结果
    fn value(&mut self, arg: u32) -> u32 {
        match self.value {
            Some(v) => v,
            None => {
                let v = (self.calculation)(arg);
                self.value = Some(v);
                v
            }
        }
    }
}